package edu.mtu.citizenscience.cs.sdk.uploader;

import edu.mtu.citizenscience.cs.utils.Services;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
/**
 * @author Corbin Uselton <corbinu@cwuselto@mtu.edu>
 * @copyright (c) 2012 MichiganTech <http://www.mtu.edu>
 * @since 1.0
 * 
 * Interacts the Uploader service to upload the apps reports in the background
 */
public class CitsciUploader {
	// messenger to the uploader service
	private Messenger messenger;
	// the uploader callbacks on the activity uploading
	private CitsciUploaderCallback callbacks;
	
	/**
	 * @since 1.0
	 * 
	 * Handles messages from the Uploader service
	 */
	@SuppressLint("HandlerLeak")
	private Handler handler = new Handler() 
	{
		/**
		 * Called when a message from the Uploader service is received
		 * 
		 * @param   message - Message - The message from the service
		 * @return	void
		 */
		public void handleMessage(Message message) 
		{
			// get the data bundle from the message
			Bundle data = message.getData();
			// if the service is working properly and sent a data bundle
			if (message.arg1 == Activity.RESULT_OK && data != null) 
			{
				// the progress update from the message
				String progress = data.getString(CitsciUploaderService.PROGRESS);
				// the report number if any being uploaded
				Integer reportNum = data.getInt(CitsciUploaderService.REPORT_NUM);
				// the file number if any being uploaded
				Integer fileNum = data.getInt(CitsciUploaderService.FILE_NUM);
				// check that got progress, report num and file num
				if (progress != null && reportNum != null && fileNum != null)
				{
					Log.d("uploader", "progress " + progress + " report num " + reportNum + " file num" + fileNum);
					// send the progress to the activity
					callbacks.uploaderProgress(CitsciUploaderProgress.valueOf(progress), reportNum, fileNum);
				}
				// get the max progress value
				Integer progressMax = data.getInt(CitsciUploaderService.PROGRESS_MAX, -1);
				// check that got progress max
				if (progressMax > -1)
				{
					Log.d("uploader", "progress max " + progressMax);
					// send the max progress to the activity
					callbacks.uploaderProgressMax(progressMax);
				}
				// get the current progress value
				Integer progressUpdate = data.getInt(CitsciUploaderService.PROGRESS_UPDATE, -1);
				// check that got progress value
				if (progressUpdate > -1)
				{
					Log.d("uploader", "progress update " + progressUpdate);
					// send the progress value to the activity
					callbacks.uploaderProgressUpdate(progressUpdate);
				}
				// get the error if any
				String error = data.getString(CitsciUploaderService.ERROR);
				// check if got error from the uploader
				if (error != null)
				{
					Log.d("uploader", "uploader error " + error);
					// send the error on to the activity
					callbacks.uploaderError(CitsciUploaderError.valueOf(error));
				}
				// get the error message if any
				String errorMessage = data.getString(CitsciUploaderService.ERROR_MESSAGE);
				// check if got error message from the uploader
				if (errorMessage != null)
				{
					Log.d("uploader", "error message " + errorMessage);
					// send the error message on to the activity
					callbacks.uploaderErrorMessage(errorMessage);
				}
				// get the upload complete if sent
				Boolean uploadComplete = data.getBoolean(CitsciUploaderService.UPLOAD_COMPLETE);
				// check if got upload complete and that it uploaded successfully
				if (uploadComplete != null && uploadComplete)
				{
					Log.d("uploader", "upload complete");
					// send upload complete on to the activity
					callbacks.uploaderUploadComplete();
				}
			}
		}
	};
	
	/**
	 * @since 1.0
	 * 
	 * Handles connecting and disconnecting from the Uploader service
	 */
	private ServiceConnection conn = new ServiceConnection() 
	{
		/**
		 * Called when the Uploader service is connected
		 * 
		 * @param   className - ComponentName - The concrete component name of the service that has been connected.
		 * @param   binder - IBinder - The IBinder of the Service's communication channel, which you can now make calls on.
		 * @return	void
		 */
	    public void onServiceConnected(ComponentName className, IBinder binder) 
	    {
	    	// create a new message from the service binder to send messages over
	    	messenger = new Messenger(binder);
	    }
	
	    /**
		 * Called when the Uploader service is disconnected
		 * 
		 * @param   className - ComponentName - The concrete component name of the service whose connection has been lost.
		 * @return	void
		 */
		public void onServiceDisconnected(ComponentName className) 
		{
			// service disconnected so clear messenger
			messenger = null;
	    }
	};
	
	/**
	 * Start the Uploader service called from App Create method
	 * 
	 * @param   context - Context - the app to create the service for
	 * @return	void
	 */
	public static void create(Context context)
	{
        context.startService(new Intent(context, CitsciUploaderService.class));
	}
	
	/**
	 * Binds the app to the Uploader service called in the activities resume method
	 * 
	 * @param   context - Context - the activity to bind the Uploader Service to
	 * @param	callbacks - CitsciUploaderCallback - the callbacks on the managing activity
	 * @return	void
	 */
	public void resume(Context context, CitsciUploaderCallback callbacks)
	{
		// new Uploader service intent
		Intent intent = new Intent(context, CitsciUploaderService.class);
		// create new messenger for this Uploader Service handler
		Messenger messenger = new Messenger(handler);
		// put the messenger in the intent
		intent.putExtra(Services.MESSENGER, messenger);

		// bind the service to this object using the ServiceConnection using the intent
		context.bindService(intent, conn, Context.BIND_AUTO_CREATE);
		
		// attach the uploader callbacks from the activity
		this.callbacks = callbacks;
	}
	
	/**
	 * Unbinds the app from the Uploader service called in the activities pause method
	 * 
	 * @param   context - Context - the activity to bind the uploader Service to
	 * @return	void
	 */
	public void pause(Context context)
	{
		// unbind the service from this object using the ServiceConnection
		context.unbindService(conn);
	}
	
	/**
	 * Start the upload
	 * 
	 * @param   mainTable - String - the main table to upload
	 * @return	boolean
	 */
	public void startUpload(String mainTable)
	{
		// check if the service messenger is attached or not
		if (this.messenger != null)
		{	
			// get a new message
			Message msg = Message.obtain();
			
			// create a new message data bundle
			Bundle bundle = new Bundle();
			// put the main table to upload in the bundle
			bundle.putString(CitsciUploaderService.MAIN_TABLE, mainTable);

			try 
			{
				// attach the data bundle to the message
				msg.setData(bundle);
				// send the message to the service
				messenger.send(msg);
			} 
			catch (RemoteException e) 
			{
				e.printStackTrace();
			}
		}
		else
		{
			Log.e("Uploader", "Attempting to send message to start CitsciUploaderService uploading but its messager is not attached");
		}
	}

}
